package com.wei.spring.web.user.advice;

import com.wei.spring.web.user.model.vo.ResultData;
import com.wei.spring.web.user.util.ResultUtil;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.ArrayList;
import java.util.List;

/**
 * 类的详细说明
 *
 * @author buhuan.wang
 * @since 2020/12/21
 */
@RestControllerAdvice
public class UnifiedResponseDataAdvice implements ResponseBodyAdvice<Object> {
    private static final List<String> IGNORE_PACKAGES = new ArrayList<String>() {
        {
            add("springfox.documentation");
            add("com.wei.spring.web.user.testcontroller");
        }
    };

    private static final List<String> IGNORE_CLASSES = new ArrayList<String>();

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return filter(methodParameter);
    }

    @Nullable
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass,
                                  ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // o is null -> return response
        if (o == null) {
            return ResultUtil.getSuccess(null);
        }
        // o is instanceof ConmmonResponse -> return o
        if (o instanceof ResultData) {
            return (ResultData) o;
        }
        // string 特殊处理
        if (o instanceof String) {
            return ResultUtil.getSuccess(o).toString();
        }
        return ResultUtil.getSuccess(o);
    }

    private Boolean filter(MethodParameter methodParameter) {
        Class<?> declaringClass = methodParameter.getDeclaringClass();
        // 检查过滤包路径
        long count = IGNORE_PACKAGES.stream()
                .filter(l -> declaringClass.getName().contains(l)).count();
        if (count > 0) {
            return false;
        }
        // 检查<类>过滤列表
        if (IGNORE_CLASSES.contains(declaringClass.getName())) {
            return false;
        }
        // 检查注解是否存在
        if (methodParameter.getDeclaringClass().isAnnotationPresent(IgnoreResponseAdvice.class)) {
            return false;
        }
        if (methodParameter.getMethod().isAnnotationPresent(IgnoreResponseAdvice.class)) {
            return false;
        }
        return true;
    }

}
